package com.yh.ldzl.service;

import com.yh.ldzl.config.websocket.QualityCheckWebSocketHandler;
import com.yh.ldzl.config.websocket.WebSocketMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 质检WebSocket服务类
 * 提供发送质检相关消息的方法
 */
@Service
public class QualityCheckWebSocketService {
    private static final Logger logger = LoggerFactory.getLogger(QualityCheckWebSocketService.class);

    // 消息去重时间窗口（毫秒）
    private static final long MESSAGE_DEDUPLICATION_WINDOW = 10000L;
    
    // 消息缓存，存储消息ID及其发送时间
    private final Map<String, Long> messageSentCache = new ConcurrentHashMap<>();
    
    // 用于缓存待合并发送的创建通知
    private final Map<String, Integer> pendingCreations = new ConcurrentHashMap<>();

    @Autowired
    private QualityCheckWebSocketHandler webSocketHandler;
    
    @PostConstruct
    public void init() {
        logger.info("质检WebSocket服务初始化，已启用消息去重机制");
    }
    
    /**
     * 检查是否是重复消息
     * 
     * @param messageKey 消息键
     * @return 如果是重复消息返回true，否则返回false
     */
    private boolean isDuplicateMessage(String messageKey) {
        long now = System.currentTimeMillis();
        Long lastSentTime = messageSentCache.get(messageKey);
        
        if (lastSentTime != null && (now - lastSentTime) < MESSAGE_DEDUPLICATION_WINDOW) {
            logger.info("检测到重复消息，已拦截: {}", messageKey);
            return true;
        }
        
        // 记录此次消息发送
        messageSentCache.put(messageKey, now);
        return false;
    }
    
    /**
     * 生成消息键
     * 
     * @param type 消息类型
     * @param inspectionId 检验单ID
     * @param inspectionType 检验类型
     * @return 消息键
     */
    private String generateMessageKey(String type, Long inspectionId, String inspectionType) {
        return type + "_" + inspectionType + "_" + inspectionId;
    }
    
    /**
     * 定时清理过期消息缓存
     * 每10分钟执行一次
     */
    @Scheduled(fixedRate = 600000)
    public void cleanupMessageCache() {
        if (messageSentCache.isEmpty()) {
            return;
        }
        
        long now = System.currentTimeMillis();
        int beforeSize = messageSentCache.size();
        
        messageSentCache.entrySet().removeIf(entry -> 
            (now - entry.getValue()) > MESSAGE_DEDUPLICATION_WINDOW * 5);
        
        int afterSize = messageSentCache.size();
        if (beforeSize > afterSize) {
            logger.info("清理过期消息缓存，清理前: {}，清理后: {}", beforeSize, afterSize);
        }
    }

    /**
     * 推送质检单创建通知
     * 
     * @param inspectionId 检验单ID
     * @param inspectionCode 检验单编号
     * @param inspectionType 检验类型
     * @param message 通知消息
     */
    public void pushQualityCheckCreated(Long inspectionId, String inspectionCode, String inspectionType, String message) {
        // 不再立即发送，而是聚合通知
        pendingCreations.merge(inspectionType, 1, Integer::sum);
        logger.info("聚合一个新的创建通知，类型: {}", inspectionType);
    }

    /**
     * 推送质检单更新通知
     * 
     * @param inspectionId 检验单ID
     * @param inspectionCode 检验单编号
     * @param inspectionType 检验类型
     * @param message 通知消息
     */
    public void pushQualityCheckUpdated(Long inspectionId, String inspectionCode, String inspectionType, String message) {
        // 生成消息键并检查是否是重复消息
        String messageKey = generateMessageKey("update", inspectionId, inspectionType);
        if (isDuplicateMessage(messageKey)) {
            return;
        }
        
        Map<String, Object> data = new HashMap<>();
        data.put("inspectionId", inspectionId);
        data.put("inspectionCode", inspectionCode);
        data.put("inspectionType", inspectionType);
        data.put("operationType", "update"); // 明确指定操作类型为更新
        // 添加唯一消息ID用于前端去重
        data.put("messageId", messageKey + "_" + System.currentTimeMillis());
        
        WebSocketMessage<Map<String, Object>> wsMessage = new WebSocketMessage<>(
            "quality_check_created", // 统一使用创建事件，由前端根据operationType区分
            message, 
            data
        );
        
        webSocketHandler.broadcastMessage(wsMessage);
        
        logger.info("推送质检单更新通知: 检验单ID={}, 检验单编号={}, 类型={}", inspectionId, inspectionCode, inspectionType);
    }

    /**
     * 推送质检进度更新消息
     * 
     * @param inspectionId 检验单ID
     * @param progress 质检进度
     * @param message 进度消息
     */
    public void pushQualityCheckProgress(Long inspectionId, String progress, String message) {
        // 生成消息键并检查是否是重复消息
        String messageKey = generateMessageKey("progress", inspectionId, progress);
        if (isDuplicateMessage(messageKey)) {
            return;
        }
        
        Map<String, Object> data = new HashMap<>();
        data.put("inspectionId", inspectionId);
        data.put("progress", progress);
        // 添加唯一消息ID用于前端去重
        data.put("messageId", messageKey + "_" + System.currentTimeMillis());
        
        WebSocketMessage<Map<String, Object>> wsMessage = new WebSocketMessage<>(
            "quality_check_progress", 
            message, 
            data
        );
        
        webSocketHandler.broadcastMessage(wsMessage);
        
        logger.info("推送质检进度更新: 检验单ID={}, 进度={}", inspectionId, progress);
    }

    /**
     * 推送质检完成消息
     * 
     * @param inspectionId 检验单ID
     * @param result 质检结果 (1=合格, 2=不合格)
     * @param message 完成消息
     */
    public void pushQualityCheckComplete(Long inspectionId, String result, String message) {
        // 生成消息键并检查是否是重复消息
        String messageKey = generateMessageKey("complete", inspectionId, result);
        if (isDuplicateMessage(messageKey)) {
            return;
        }
        
        Map<String, Object> data = new HashMap<>();
        data.put("inspectionId", inspectionId);
        data.put("result", result);
        data.put("resultText", "1".equals(result) ? "合格" : "不合格");
        // 添加唯一消息ID用于前端去重
        data.put("messageId", messageKey + "_" + System.currentTimeMillis());
        
        WebSocketMessage<Map<String, Object>> wsMessage = new WebSocketMessage<>(
            "quality_check_complete", 
            message, 
            data
        );
        
        webSocketHandler.broadcastMessage(wsMessage);
        
        logger.info("推送质检完成: 检验单ID={}, 结果={}", inspectionId, result);
    }
    
    /**
     * 定时任务，用于发送聚合后的创建通知
     */
    @Scheduled(fixedDelay = 10000L)
    public void sendBatchedCreationNotifications() {
        if (pendingCreations.isEmpty()) {
            return;
        }

        // 创建一个副本进行处理，并清空原map，避免并发问题
        Map<String, Integer> creationsToSend = new HashMap<>(pendingCreations);
        pendingCreations.clear();

        creationsToSend.forEach((inspectionType, count) -> {
            if (count > 0) {
                String typeName = getInspectionTypeName(inspectionType);
                String summaryMessage = String.format("有 %d 个新的%s已创建，请及时处理。", count, typeName);

                Map<String, Object> data = new HashMap<>();
                data.put("inspectionType", inspectionType);
                data.put("count", count);
                data.put("operationType", "create_batch");
                data.put("messageId", "batch_create_" + inspectionType + "_" + System.currentTimeMillis());

                WebSocketMessage<Map<String, Object>> wsMessage = new WebSocketMessage<>(
                    "quality_check_created",
                    summaryMessage,
                    data
                );

                webSocketHandler.broadcastMessage(wsMessage);
                logger.info("发送聚合创建通知: {}", summaryMessage);
            }
        });
    }

    /**
     * 辅助方法，根据检验类型ID获取中文名称
     * @param inspectionType 检验类型ID
     * @return 检验类型中文名称
     */
    private String getInspectionTypeName(String inspectionType) {
        switch (inspectionType) {
            case "1": return "来料检验单";
            case "2": return "过程检验单";
            case "3": return "出货检验单";
            case "4": return "退料检验单";
            default: return "检验单";
        }
    }

    /**
     * 推送工作报告生成质检单通知
     * 
     * @param inspectionId 检验单ID
     * @param inspectionCode 检验单编号
     * @param inspectionType 检验类型
     * @param sourceDocId 源单据ID
     * @param message 通知消息
     */
    public void pushWorkReportQcCreated(Long inspectionId, String inspectionCode, String inspectionType, 
                                      Long sourceDocId, String message) {
        String consolidationKey = "create_work_report_" + inspectionType;
        // if (isDuplicateMessage(consolidationKey)) {
        //     logger.info("合并工作报告质检创建通知，已拦截: type={}", inspectionType);
        //     return;
        // }
        
        Map<String, Object> data = new HashMap<>();
        data.put("inspectionId", inspectionId);
        data.put("inspectionCode", inspectionCode);
        data.put("inspectionType", inspectionType);
        data.put("sourceDocId", sourceDocId);
        data.put("messageId", consolidationKey + "_" + System.currentTimeMillis());
        
        WebSocketMessage<Map<String, Object>> wsMessage = new WebSocketMessage<>(
            "work_report_qc_created", 
            message, 
            data
        );
        
        webSocketHandler.broadcastMessage(wsMessage);
        
        logger.info("推送工作报告质检通知: {}", message);
    }

    /**
     * 推送给指定用户
     * 
     * @param userId 用户ID
     * @param type 消息类型
     * @param message 消息内容
     * @param data 消息数据
     */
    public <T> void pushToUser(String userId, String type, String message, T data) {
        // 对于定向消息，不做去重处理
        WebSocketMessage<T> wsMessage = new WebSocketMessage<>(type, message, data);
        webSocketHandler.sendMessageToUser(userId, wsMessage);
    }

    /**
     * 获取当前WebSocket连接数
     */
    public int getConnectionCount() {
        return webSocketHandler.getConnectionCount();
    }
    
    /**
     * 获取当前消息缓存大小
     */
    public int getMessageCacheSize() {
        return messageSentCache.size();
    }
    
    /**
     * 清空消息缓存（用于测试或重置）
     */
    public void clearMessageCache() {
        int size = messageSentCache.size();
        messageSentCache.clear();
        logger.info("手动清空消息缓存，清理数量: {}", size);
    }
}
